import { onUnmounted, ref, watchEffect } from 'vue'
import { defineStore } from 'pinia'
import Lyric from 'lrc-file-parser'
import { PLAYER_STATUS, PLAYER_INFO } from '@/common/constant'
import { getPlayer, setInfo } from '@/common/player'
import { getRandomNumber, getIndex, setValue } from '@/common/utils'
import { getMeting } from '@/common/http.api'

// 播放器状态
const audioStatus = PLAYER_STATUS

let currentLyric = {}

export const usePlayerStore = defineStore(
  'player',
  () => {
    /**
     * state
     */
    // 歌曲正在加载中
    const loading = ref(false)

    // 播放队列
    const playerQueue = ref([])

    // 当前播放歌曲信息
    const playerInfo = ref({})

    // (歌曲、歌单)收藏数据
    const playerCollect = ref({ songlist: [], playlist: [] })

    // 播放器状态信息
    const playerStatus = ref(audioStatus)

    /**
     * 方法
     */

    /**
     * 设置加载状态
     * @param {*} status true/false
     */
    const setLoading = (status) => {
      setValue({ target: loading, value: status })
    }

    /**
     * 初始化音频组件状态
     */
    const setInitAudioManager = () => {
      const player = getPlayer()

      // 设置音频
      player.pause()
      player.stop()
      player.currentTime = 0
      player.playbackRate = playerStatus.value.playbackRate
      // 设置状态
      setPlayerStatus({
        currentTime: 0,
        duration: 0,
        percent: 0,
        paused: true,
      })
    }

    /**
     * 加载歌曲信息
     */
    const loadSong = async (song) => {
      const player = getPlayer()
      const args = song ? song : playerInfo.value

      // 显示加载
      setLoading(true)

      // 当存在播放记录，但播放器没有初始化src时
      const lyric = await loadLyric(args.id)
      // #ifdef MP
      const url = await getMeting(args.id, 'url')
      args.url = url
      // #endif

      // 有歌曲地址，设置音频信息
      if (args.url) {
        setInfo(args)
        // 有播放歌曲就播放
        if (!playerStatus.value.paused) player.play()
      }

      // 添加歌词，播放属性
      const songInfo = { ...args, lyric, play: !playerStatus.value.paused }

      // 设置当前歌曲信息
      setValue({ target: playerInfo, value: songInfo })
    }

    /**
     * 加载歌曲歌词信息
     */
    const loadLyric = async (id) => {
      const lyric = await getMeting(id, 'lrc')

      // #ifdef H5
      currentLyric = new Lyric({ lyric })
      // 如果当前歌曲为播放状态，调用歌词对象的播放方法，播放歌词
      return currentLyric.lines
      // #endif
      // #ifdef MP
      const newLyric = lyric.map((lrc) => {
        return Object.assign({}, lrc, {
          text: lrc.lineLyric,
          time: parseInt(lrc.time) * 1000,
        })
      })
      return newLyric
      // #endif
    }

    /**
     * 选歌，获取歌曲信息
     * @param {*} song
     */
    const setPlayerInfo = async (song) => {
      const player = getPlayer()

      // 点击播放歌曲与当前播放歌曲一样，就只切换播放、暂停功能，否则就切换歌曲
      if (song.id === playerInfo.value.id) {
        if (player.paused) player.play()
        else player.pause()
        return
      }

      // 初始化播放器状态信息
      setInitAudioManager()
      // 如果上一首歌是插队列表的歌，把他的插队标记取消
      const curSongIdx = getIndex(playerQueue.value, song.id)
      const curSongInfo = playerQueue.value[curSongIdx]

      // 存在插入值，执行
      if (curSongInfo?.preference) curSongInfo.preference = false
      // 获取歌曲音源，歌曲播放
      await loadSong(song)
      player.play()
      console.log(playerInfo.value)
      // 添加播放队列
      setPreference(playerInfo.value, false)
    }

    /**
     * 更改播放器状态
     */
    const setPlayerStatus = (args) => {
      const info = args ? args : audioStatus
      const newInfo = Object.assign({}, playerStatus.value, info)

      setValue({ target: playerStatus, value: newInfo })
    }

    // 更新歌曲是否播放状态
    const setSongPlayStatus = (status) => {
      // 设置播放状态
      setPlayerStatus({ paused: !status })
      // 设置当前歌曲播放状态
      playerInfo.value.play = status
    }

    /**
     * 切换播放模式
     * @param {*} mode
     */
    const setPlayerMode = (mode) => {
      let title = ['循环播放', '随机播放', '单曲播放']

      mode += 1
      if (mode > 2) mode = 0
      setPlayerStatus({ mode: mode })

      // 提示
      uni.$u.toast(title[mode])
    }

    /**
     * 切换播放倍速
     * @param {*} type
     */
    const setPlaybackRate = (type) => {
      const player = getPlayer()

      if (type == 1.0) type = 1.25
      else if (type == 1.25) type = 1.5
      else if (type == 1.5) type = 2.0
      else if (type == 2.0) type = 1.0

      setPlayerStatus({ playbackRate: type })
      player.playbackRate = type
      // 提示
      uni.$u.toast(`${type}倍速`)
    }

    /**
     * 调整歌曲进度
     */
    const setSeek = (time) => {
      const player = getPlayer()

      if (player.src) {
        player.seek(time)
        if (player.paused) player.play()
      } else {
        //调整歌曲事件时，歌曲在加载状态，等待加载完成后再设置
        uni.$once('onCanplay', () => player.seek(time))
        loadSong()
      }
    }

    /**
     * 开始播放
     */
    const setPlayerPlay = () => {
      const player = getPlayer()

      // 播放队列没有歌曲执行
      if (playerQueue.value.length === 0)
        return uni.$u.toast('播放队列没有歌曲~')

      if (player.src) player.play()
      else loadSong()
    }

    /**
     * 暂停播放
     */
    const setPlayerPause = () => {
      const player = getPlayer()

      if (player.src) player.pause()
      else loadSong()
    }

    /**
     * 切歌处理
     */
    const changAirHandler = () => {
      if (playerQueue.value.length > 0) {
        const preferenceList = playerQueue.value.filter((v) => {
          return v?.preference && v.id !== playerInfo.value.id
        })
        console.log(preferenceList, '---0')
        if (preferenceList.length > 0) return preferenceList
        else return playerQueue.value
      } else {
        return undefined
      }
    }

    /**
     * 上一首
     */
    const setPlayerPrev = () => {
      const list = changAirHandler()

      if (list !== undefined) {
        const curSongRid = playerInfo.value.id
        const curSongIdx = getIndex(playerQueue.value, curSongRid)
        // 获取上一首歌曲的下标
        const prevSongIdx = curSongIdx === 0 ? list.length - 1 : curSongIdx - 1
        // 获取上一首歌曲的信息
        const prevSongInfo = list[prevSongIdx]

        setPlayerInfo(prevSongInfo)
      } else {
        uni.$u.toast('播放队列已空~')
        setValue({ target: playerInfo, value: PLAYER_INFO })
        setPlayerStatus({
          currentTime: 0,
          duration: 0,
          percent: 0,
          buffered: 0,
          paused: true,
        })
      }
    }

    /**
     * 下一首
     */
    const setPlayerNext = () => {
      const list = changAirHandler()

      if (list !== undefined) {
        // 判断当前播放模式
        const curMode = playerStatus.value.mode
        // 播放队列长度
        const queueLength = list.length
        // 当前播放歌曲rid
        const curSongRid = playerInfo.value.id
        // 获取当前歌曲在播放队列里的下标
        const curSongIdx = getIndex(list, curSongRid)
        // 下一首歌曲的下标
        let nextSongIdx = undefined

        // 根据播放模式设置下一首歌曲的下标
        if (curMode === 0) {
          // 循环播放
          nextSongIdx = curSongIdx >= queueLength - 1 ? 0 : curSongIdx + 1
        } else if (curMode === 1) {
          // 随机播放
          nextSongIdx = getRandomNumber(0, queueLength - 1)
        } else if (curMode === 2) {
          // 单曲循环
          nextSongIdx = curSongIdx
        }
        console.log(nextSongIdx, 'ni', 'mode:', curMode)
        // 存在下一首下标，执行播放
        if (nextSongIdx !== undefined) {
          const nextSongInfo = list[nextSongIdx]

          setPlayerInfo(nextSongInfo)
        } else {
          uni.$u.toast('已经是最后一首了')
        }
      } else {
        uni.$u.toast('播放队列已空~')
        setValue({ target: playerInfo, value: PLAYER_INFO })
        setPlayerStatus({
          currentTime: 0,
          duration: 0,
          percent: 0,
          buffered: 0,
          paused: true,
        })
      }
    }

    /**
     * 插入播放队列
     * @param {*} song
     */
    const setPreference = (song, preference = true) => {
      const curSongIdx = getIndex(playerQueue.value, song.id)

      // 设置队列标识
      song.addQueue = true
      // 判断队列是否存在
      if (curSongIdx > -1) {
        playerQueue.value[curSongIdx].preference = preference ? true : false
        playerQueue.value[curSongIdx].addQueue = true
      } else {
        // 添加队列
        playerQueue.value.unshift({
          ...song,
          preference: preference ? true : false,
        })
      }
      // 是插入队列就提示
      if (preference) uni.$u.toast('已加入播放队列~')
    }

    /**
     * 全部加入播放队列
     * @param {*} songList 数据
     */
    const setAddAllSongQueue = async (songList) => {
      const player = getPlayer()
      // 随机队列歌曲索引
      const randomIdx = getRandomNumber(0, songList.length - 1)
      // 添加到队列
      songList.forEach((song) => {
        // 当前歌曲在队列索引
        const curSongIdx = playerQueue.value.findIndex((v) => v.id === song.id)
        // 不存在队列执行添加到队列
        if (curSongIdx < 0) {
          console.log(curSongIdx, '不存在队列中')
          song.addQueue = true
          playerQueue.value.push(song)
        }
      })
      // 不存在当前播放歌曲，就执行获取队列索引为0的歌曲数据
      if (!playerInfo.value.id) {
        await loadSong(songList[randomIdx])
        player.play()
      }
      // 提示
      uni.$u.toast('加入队列成功~')
      // 显示小播放器
      setPlayerStatus({ smallPlayer: true })
    }

    /**
     * 加入播放队列
     * @param {*} song
     */
    const setAddSongQueue = async (song) => {
      const player = getPlayer()
      // 随机获取队列歌曲索引
      const songIdx = getRandomNumber(0, playerQueue.value.length - 1)
      // 显示小播放器
      setPlayerStatus({ smallPlayer: true })
      // 插入队列
      setPreference(song)
      // 没有播放且没有当前歌曲信息，执行以下
      if (!playerInfo.value.url) {
        const songInfo = playerQueue.value[songIdx]

        console.log('加载歌曲', songInfo)
        // 加载歌曲
        await loadSong(songInfo)
        player.play()
      }
    }

    /**
     * 删除队列歌曲
     * @param {*} id ID
     * @param {*} type 类型-0：播放队列，1：收藏歌曲，2：收藏歌单
     */
    const setDelShareQueue = (id, type = 0) => {
      // type - 0：播放队列
      if (type === 0) {
        const curQueueIdx = getIndex(playerQueue.value, id)

        // 删除歌曲
        playerQueue.value.splice(curQueueIdx, 1)
        // 删除歌曲与当前播放歌曲一样，就执行下一首
        if (playerInfo.value?.id === id) {
          setPlayerNext()
        }
        // 提示
        uni.$u.toast('已删除歌曲~')
      } else if (type === 1) {
        // 1：收藏歌曲
        const curLikeSongIdx = getIndex(playerCollect.value.songlist, id)
        // 移除喜欢歌曲
        playerCollect.value.songlist.splice(curLikeSongIdx, 1)
        // 当前歌曲是否和移除歌曲相等，是就改变当前播放歌曲喜欢状态
        if (playerInfo.value.id === id) playerInfo.value.like = false
        playerQueue.value.filter((song) => {
          if (song.id === id) song.like = false
          return song
        })
        // 提示
        uni.$u.toast('已移除歌曲~')
      } else {
        // 2：收藏歌单
        // 获取在歌单收藏索引
        const curLikeIdx = getIndex(playerCollect.value.playlist, id)
        // 删除收藏
        playerCollect.value.playlist.splice(curLikeIdx, 1)
      }
    }

    /**
     * 清空队列
     */
    const clearQueue = () => {
      if (playerQueue.value.length > 0) {
        setInitAudioManager()
        setSongPlayStatus(false)
        setValue([
          {
            target: playerInfo,
            value: PLAYER_INFO,
          },
          { target: playerQueue, value: [] },
        ])
      }
    }

    /**
     * 加入收藏歌曲
     * @param {*} song
     */
    const setLikeSong = (song) => {
      // 获取在喜欢队列里是否存在歌曲下标
      const curLikeSongIdx = getIndex(playerCollect.value.songlist, song.id)
      const curQueueSongIdx = getIndex(playerQueue.value, song.id)

      if (curLikeSongIdx > -1) {
        song.like = false
        // 取消收藏
        setDelShareQueue(song.id, 1)
      } else {
        song.like = true
        // 设置数据 Like 值
        playerQueue.value[curQueueSongIdx].like = song.like
        // 添加收藏
        playerCollect.value.songlist.unshift(song)
      }
      // 提示文字
      const tip = song.like ? '已添加' : '已移除'

      // 提示
      uni.$u.toast(`${tip}歌曲收藏~`)
    }

    /**
     * 收藏喜欢歌单
     * @param {*} song
     */
    const setLikePlaylist = (playlist) => {
      // 获取在歌单收藏索引
      const curLikeIdx = getIndex(playerCollect.value.playlist, playlist.id)

      // 根据条件收藏/不收藏做事情
      if (curLikeIdx < 0) {
        // 设置收藏
        playlist.like = true
        // 添加收藏
        playerCollect.value.playlist.unshift(playlist)
      } else {
        // 设置不收藏
        playlist.like = false
        // 取消收藏
        setDelShareQueue(playlist.id, 2)
      }
      // 提示
      uni.$u.toast(`已${playlist.like ? '添加' : '取消'}收藏歌单~`)
    }

    /**
     * 设置播放器信息
     */
    const initPlayer = async () => {
      // 判断是否不是空对象
      if (Object.keys(playerInfo.value).length > 0 && playerInfo.value?.url) {
        const player = getPlayer()
        // 获取当前歌曲在队列索引
        const curQueueIdx = getIndex(playerQueue.value, playerInfo.value.id)
        // 显示小播放器
        setPlayerStatus({ smallPlayer: true })
        // 当前队列存在，就根据播放歌曲设置播放器信息
        if (curQueueIdx > -1) {
          if (playerStatus.value.paused) {
            console.log('init-paused')
            // 设置歌曲信息
            await loadSong(playerQueue.value[curQueueIdx])
            // 设置听歌时间
            player.seek(playerStatus.value.currentTime)
          } else {
            console.log('init-play')
            // 跳转当前歌曲播放时间播放
            setSeek(playerStatus.value.currentTime)
          }
        }
        console.log('init-seek')
      } else {
        console.log('init-random')
        if (playerQueue.value.length > 0) {
          // 随机获取队列歌曲索引
          const songIdx = getRandomNumber(0, playerQueue.value.length - 1)
          // 加载歌曲
          await loadSong(playerQueue.value[songIdx])
        } else {
          // 初始化播放状态
          setPlayerStatus({ ...PLAYER_STATUS, smallPlayer: false })
        }
      }
    }

    /**
     * 切换播放器(大/小)
     * @param {*} status
     */
    const switchPlayer = (status) => {
      // 播放队列没有歌曲执行
      if (playerQueue.value.length === 0)
        return uni.$u.toast('播放队列没有歌曲~')
      // 切换播放器
      setPlayerStatus({
        smallPlayer: !status,
        bigPlayer: status,
      })
    }

    // 监听-添加标识
    const stopWatch = watchEffect(() => {
      // 根据队列歌曲在列表设置队列标识
      playerQueue.value.forEach((song) => {
        // 获取歌曲喜欢索引
        const curSongLikeIdx = getIndex(playerCollect.value.songlist, song.id)

        song.like = curSongLikeIdx > -1
      })
    })

    // 停止侦听器
    onUnmounted(() => stopWatch())

    return {
      playerInfo,
      playerStatus,
      playerQueue,
      playerCollect,
      loading,
      initPlayer,
      switchPlayer,
      setLoading,
      setSeek,
      setSongPlayStatus,
      setPreference,
      setPlayerInfo,
      setPlayerStatus,
      setPlayerMode,
      setPlayerPlay,
      setPlayerPause,
      setPlayerPrev,
      setPlayerNext,
      setPlaybackRate,
      setAddSongQueue,
      setAddAllSongQueue,
      setDelShareQueue,
      setLikeSong,
      setLikePlaylist,
      clearQueue,
    }
  },
  {
    persist: true, // 开启后对 state 的数据读写都将持久化
  }
)
